package cn.learn.async;

import cn.learn.async.domian.TaskDemo;
import cn.learn.async.service.AsyncService3;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * 背景：
 * 使用异步 servlet 主要原因就是因为，在 service 方法中业务逻辑如果碰到 io 操作时间比较长的操作，这样这个 service 方法就会长时间占用 tomcat 容器线程池中的线程，
 * 这样是不利于其他请求的处理的，当线程池中的线程处理任务时，任务由于长时间 io 操作，肯定会阻塞线程处理其他任务，引入异步 servlet 的目的就是将容器线程池和业务线程池分离开。
 * 在处理大 io 的业务操作的时候，把这个操作移动到业务线程池中进行，释放容器线程，使得容器线程处理其他任务，在业务逻辑执行完毕之后，再通知 tomcat 容器线程池来继续后面的操作，
 * 这个操作应该是把处理结果 commit 到客户端或者是 dispatch 到其他 servlet 上。原始模型在处理业务逻辑的过程中会一直占有容器线程池，而异步 servlet 模型，在业务线程池处理的过程中，
 * 有一段时间容器线程池中的那个线程是空闲的，这种设计大大提高了容器的处理请求的能力
 * <p>
 * DeferredResult 和 Callable 都是为了异步生成返回值提供基本的支持。简单来说就是一个请求进来，如果你使用了 DeferredResult 或者 Callable，在没有得到返回数据之前，
 * DispatcherServlet 和所有 Filter 就会退出 Servlet 容器线程并释放其资源，同时也允许容器去处理其它请求。但响应保持打开状态，一旦返回数据有了，
 * 这个 DispatcherServlet 就会被再次调用并且处理，以异步产生的方式，向请求端返回值。
 * 这么做的好处就是请求不会长时间占用服务连接池，提高服务器的吞吐量
 * <p>
 * <p>
 * 线程超时管理的处理？
 * <p>
 * <p>
 * 启用异步多线程来处理rest服务，一般有这两种处理方式Callable、DeferredResult
 * 异步线程Callable、DeferredResult、Future
 *
 * @author huangyezhan
 * @date 2020年02月13日23:08
 */
@Slf4j
@RestController
public class AsyncControllerDemo {


    /**
     * Callable 的实现比较简单，call() 方法的返回值就是服务端返回给请求端的数据
     *
     * @return
     */
    @RequestMapping(value = "/order", method = RequestMethod.GET)
    public Callable<String> order() {
        log.info("主线程开始");
        Callable<String> result = new Callable<String>() {
            @Override
            public String call() throws Exception {
                log.info("副线程开始");
                Thread.sleep(2000);
                log.info("副线程结束");
                return "success-成功返回结果";
            }
        };


        log.info("主线程结束");
        return result;
    }

    /**
     * lambda表达式
     *
     * @return
     */
    @RequestMapping(value = "lambda/order", method = RequestMethod.GET)
    public Callable<String> orderLambda() {
        log.info("主线程开始");
        Callable<String> result = () -> {
            log.info("副线程开始");
            Thread.sleep(2000);
            log.info("副线程结束");
            return "success-成功返回结果";
        };
        log.info("主线程结束");
        return result;
    }


    @Resource
    private AsyncService3 asyncService3;

    @RequestMapping(value = "task", method = RequestMethod.GET)
    public List<TaskDemo> taskDemo() {
        long           start = System.currentTimeMillis();
        List<TaskDemo> tasks = new ArrayList<>();
        for (int i = 1; i <= 500; i++) {
            tasks.add(new TaskDemo().setId(i).setName("张三_" + i));
        }
        List<Future<TaskDemo>> futures = new ArrayList<>();
        for (TaskDemo task : tasks) {
            futures.add(asyncService3.testAsync1(task));
        }
        try {
            for (Future<TaskDemo> future : futures) {
                future.get();
            }
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("=======================结束耗时========================");
        long hs = System.currentTimeMillis() - start;
        System.out.println(hs / 1000);
        return tasks;
    }


}
